import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# show all data when printing
pd.set_option('display.max_rows', None, 'display.max_columns', None, 'display.max_colwidth', 1000, 'display.expand_frame_repr', False)

# load data
df = pd.read_csv(r'../../../../large_data/共享单车/train.csv')
m = len(df)
# columns:
# datetime  season  holiday  workingday  weather  temp   atemp  humidity  windspeed  casual  registered  count
# atemp 体感温度？
# casual 未注册用户租赁数
# registered 注册用户租赁数
# count = casual + registered

# split
from sklearn.model_selection import train_test_split
offset_orig = range(m)
offset_train, offset_test = train_test_split(offset_orig, train_size=0.75,
                                     random_state=666)

# fig group
fig, axes = plt.subplots(nrows=2, ncols=3)
fig.set_size_inches(12, 10)

# extract date and time
# 2011-07-10 04:00:00
import calendar
from datetime import datetime
df['date'] = df['datetime'].apply(lambda x: x.split(sep=' ')[0])
df['monthnum'] = df['date'].apply(lambda x: int(x.split(sep='-')[1]), 10)
df['month'] = df['monthnum'].apply(lambda x: calendar.month_name[x])
# plot monthnum-count
df.monthnum.value_counts().sort_index().plot(kind='line', ax=axes[0][0])
df['daynum'] = df['datetime'].apply(lambda x: int(x.split(' ')[0].split('-')[2], 10))
df['hour'] = df['datetime'].apply(lambda x: int(x.split(' ')[1].split(':')[0], 10))
df['weekday'] = df['date'].apply(lambda x: calendar.day_name[datetime.strptime(x, '%Y-%m-%d').weekday()])


def hour_section(h):
    if h <= 6:
        return 0
    elif h <= 10:
        return 1
    elif h <= 15:
        return 2
    elif h <= 20:
        return 3
    else:
        return 4


df['hour_section'] = df.hour.apply(hour_section)

# process noise

# check noise in boxplot
sns.boxplot(data=df.iloc[offset_train], y='count', ax=axes[0][1])
sns.boxplot(data=df.iloc[offset_train], y='count', x='season', ax=axes[0][2])
sns.boxplot(data=df.iloc[offset_train], y='count', x='hour', ax=axes[1][0])
sns.boxplot(data=df.iloc[offset_train], y='count', x='workingday', ax=axes[1][1])

# get noise index
mu_count = df.loc[offset_train, 'count'].mean(axis=0)
sigma_count = df.loc[offset_train, 'count'].std(axis=0)
idx_bad_np = abs(df.loc[offset_train, 'count'] - mu_count) > 3 * sigma_count
idx_good_np = np.invert(idx_bad_np)
# remove noise index
print(f'Before removal: sum(idx good) = {sum(idx_good_np)}, sum(idx bad) = {sum(idx_bad_np)}, len(df[train]) = {len(df.iloc[offset_train])}')
offset_train = list(set(offset_train) - set(np.array(offset_train)[idx_bad_np]))
print(f'After removal: sum(idx good) = {sum(idx_good_np)}, sum(idx bad) = {sum(idx_bad_np)}, len(df[train]) = {len(df.iloc[offset_train])}')
# check again
idx_bad_np = abs(df.loc[offset_train, 'count'] - mu_count) > 3 * sigma_count
print(f'Check sum(idx bad) after removal: {sum(idx_bad_np)}')

# tmp
# import sys
# sys.exit(0)

# fig group 2
fig, axes = plt.subplots(nrows=2, ncols=2)
fig.set_size_inches(12, 10)
sns.boxplot(data=df.iloc[offset_train], y='count', ax=axes[0][0])
sns.boxplot(data=df.iloc[offset_train], y='count', x='season', ax=axes[0][1])
sns.boxplot(data=df.iloc[offset_train], y='count', x='hour', ax=axes[1][0])
sns.boxplot(data=df.iloc[offset_train], y='count', x='workingday', ax=axes[1][1])

# fig group 3
fig, axes = plt.subplots(nrows=2, ncols=3)
fig.set_size_inches(12, 10)

# analysis

# corr => remove feature duplicated
xcorr = df[['temp', 'atemp', 'casual', 'registered', 'humidity', 'windspeed', 'count']].corr()
sns.heatmap(xcorr, annot=True, ax=axes[0][0])
print(df.shape)  # before
df.drop(labels=['atemp', 'casual', 'registered'], axis=1, inplace=True)
print(df.shape)  # after

# pandas bar: season-count
df.groupby('season').agg(np.mean)['count'].plot(kind='bar', ax=axes[0][1])

# pandas bar: monthnum-count
df.groupby('monthnum').agg(np.mean)['count'].plot(kind='bar', ax=axes[0][2])

# sns directly: hour-season-count
sns.pointplot(data=df.iloc[offset_train], x='hour', y='count', hue='season', ax=axes[1][0])

# sns fetch-before-drawing: hour-season-count
hour_ = df.iloc[offset_train].groupby(['hour', 'season'], sort=True)['count'].mean().reset_index()
sns.pointplot(data=hour_, x='hour', y='count', hue='season', ax=axes[1][1])

# sns fetch-before-drawing: hour-weekday-count
hour_ = df.iloc[offset_train].groupby(['hour', 'weekday'], sort=True)['count'].mean().reset_index()
sns.pointplot(data=hour_, x='hour', y='count', hue='weekday', ax=axes[1][2])

# add hour_week_section


def b(h, weekday):
    if weekday not in set(['Saterday', 'Sunday']):
        # workdays
        if h <= 6:
            return 0
        elif h <= 10:
            return 1
        elif h <= 15:
            return 2
        elif h <= 20:
            return 3
        else:
            return 4
    else:
        # weekdays
        if h <= 8:
            return 5
        elif h <= 20:
            return 6
        else:
            return 7


df['hour_week_section'] = df.apply(lambda  x: b(x['hour'], x['weekday']), axis=1)
print(df[:5])

plt.show()
